import getEnv from './env'
import { ElMessage } from 'element-plus'

import user from '../store/user'

enum ResponseCode {
  success = 200,
  fail = 500
}

function download({ file, filename }: ResponseFile) {
  const a = document.createElement('a')
  a.href = URL.createObjectURL(file)
  a.target = '_blank'
  a.download = decodeURI(filename)
  document.body.appendChild(a)
  a.click()
  document.body.removeChild(a)
}

function setParams(params: Params | undefined) {
  let url = ''
  if (!params) return url
  Object.keys(params).forEach((key, index) => {
    if (typeof params[key] === 'string' || typeof params[key] === 'number') {
      url += `${index ? '&' : '?'}${key}=${params[key]}`
    }
  })
  return url
}

class Request {
  public api: string
  public baseURL: string
  public params: Params | undefined
  public headers: HeadersInit | undefined
  public timeout: number
  public url: string
  public method: Method
  public data: unknown

  constructor(ro: RequestOptions) {
    // 设置默认api
    this.api = ro.api!
    // 设置默认baseURL
    this.baseURL = ro.baseURL!
    // 设置默认params
    this.params = ro.params
    // 设置默认headers
    this.headers = ro.headers
    // 设置默认timeout
    this.timeout = ro.timeout!
    // 设置默认url
    this.url = ro.url
    // 设置默认method
    this.method = ro.method
    // 设置默认data
    this.data = ro.data
  }

  async create(successFn: SuccessFn, errorFn: ErrorFn) {
    const controll = new AbortController()
    const timer = setTimeout(() => {
      if (!this.timeout) return
      controll.abort()
    }, this.timeout)

    try {
      const response = await fetch(this.api + this.baseURL + this.url + setParams(this.params), {
        method: this.method,
        headers: this.headers as HeadersInit,
        body: this.data as BodyInit,
        signal: controll.signal
      })
      if (response.ok) {
        successFn(response)
      } else {
        errorFn(new Error(response.statusText))
      }
    } catch (e) {
      errorFn(e as Error)
    } finally {
      clearInterval(timer)
    }
  }
}

async function create<T>(requestInfo: RequestOptions): Promise<CtmResponse<T>> {
  //设置默认值
  const ro = Object.assign(
    {
      api: getEnv('api'),
      baseURL: getEnv('baseURL'),
      timeout: getEnv('timeout'),
      headers: {},
      requestType: 'json',
      responseType: 'json',
      errorMsg: true,
      downloadFile: true
    },
    requestInfo
  ) as RequestOptions

  //development环境下走代理
  if (getEnv('mode') === 'development') ro.api = ''

  // 如果是json请求，需要转换数据格式，并设置请求头
  if (ro.requestType === 'json') {
    ro.data = JSON.stringify(ro.data)
    ro.headers!['Content-Type'] = 'application/json'
  }

  // 设置token
  ro.headers!['Authorization'] = 'Bearer ' + user.token

  return new Promise((resolve, reject) => {
    new Request(ro).create(
      async (response: Response) => {
        if (ro.responseType === 'json') {
          const json = (await response.json()) as CtmResponse<T>
          if (Number(json.code) !== ResponseCode.success) {
            // 错误处理
            if (ro.errorMsg) ElMessage.error(json.msg)
            reject(json)
          } else {
            // 正常返回
            resolve(json)
          }
        } else {
          const responseFile: ResponseFile = {
            file: await response.blob(),
            filename: (ro.filename || response.headers.get('Content-Disposition')?.split('=')[1])!
          }

          if (ro.downloadFile) download(responseFile)

          resolve({
            code: ResponseCode.success,
            data: responseFile as T,
            msg: ''
          })
        }
      },
      (e) => {
        const resp = {
          code: ResponseCode.fail,
          data: null,
          msg: e.message
        }
        if (e.name === 'AbortError') resp.msg = '请求超时'
        if (ro.errorMsg) ElMessage.error(resp.msg)
        reject(resp)
      }
    )
  })
}

export default create

export { download }
